using System;
using System.Text;
using System.Collections.Generic;
using System.Net.Sockets;

namespace Demo_G.O.S.E.ServerEngine.AIEngine.Agent
{
    /// <summary>
    /// This is a Socket-based connection to another machine.
    ///  This is implemented as a DaemonService because of the Garbage Collecting capabilities built into the AgentThread and Daemon.
    /// </summary>
    public class DaemonSocket : DaemonService
    {
        /// <summary>
        /// A handle to the parent Daemon.
        /// </summary>
        //private Daemon daemon;

        /** The Socket that is connected to another machine. */
        //Socket socket;

        /** The output stream. */
        //private ObjectOutputStream outputStream;

        /** The input stream. */
        //private ObjectInputStream inputStream;

        /// <summary>
        /// The default timeout in milliseconds.
        /// </summary>
        //private static int TIMEOUT = 1000 * 6000;

        /// <summary>
        /// The hostname.
        /// </summary>
        String hostName = string.Empty;

        /// <summary>
        /// The port.
        /// </summary>
        int port = 0;

        /// <summary>
        /// A counter for determining when to reset the output stream.
        /// </summary>
        //int resetCount = 0;

        /// <summary>
        /// Constructs a new DaemonSocket for the given Socket.
        /// </summary>
        /// <param name="daemon">The Daemon whom we're working for.</param>
        /// <param name="socket">The socket for the connection.</param>
        public DaemonSocket( Daemon daemon, Socket socket )
        {
            //super( false );
            //if ( daemon == null )
            //    throw new NullPointerException( "Null Daemon" );
            //if ( socket == null )
            //    throw new NullPointerException( "Null Socket" );
            //this.daemon = daemon;
            //this.socket = socket;
            //this.hostName = socket.getInetAddress().getHostName();
            //this.port = socket.getPort();
            //try
            //{
            //    socket.setSoTimeout( TIMEOUT );
            //}
            //catch ( SocketException se )
            //{
            //    se.printStackTrace();
            //}
        }

        /// <summary>
        /// Runs this connection.
        /// </summary>
        protected void ExecuteSocket()
        {
            //try {
            //    transmitDescription(daemon.getDescription());
            //    //DSInputStream ds = new DSInputStream(socket.getInputStream());
            //    inputStream = new ObjectInputStream(socket.getInputStream());
            //    while(true) {
            //    /*
            //      // This appears to have no effect on "resetting" the timeout,
            //      // so I'm just gonna cut it out for right now.
            //    try {
            //        socket.setSoTimeout(TIMEOUT);
            //    } catch(SocketException se) {
            //        se.printStackTrace();
            //    }
            //    */
            //    try {
            //        Object o = inputStream.readObject();
            //        if(o instanceof AgentGram) {
            //        daemon.receiveAgentGram((AgentGram)o, this);
            //        } else if(o instanceof DaemonDescription) {
            //        daemon.receiveDescription((DaemonDescription)o, this);
            //        } else {
            //        String msg = "Ignoring object (" +
            //            o.getClass().getName() + ") from " + hostName;
            //        daemon.displayMessage(msg);
            //        }
            //    } catch(ClassNotFoundException cnfe) {
            //        daemon.displayMessage("Class not found: " + cnfe);
            //    } catch(OptionalDataException ode) {
            //        daemon.displayMessage("Not object: " + ode);
            //    }
            //    }
            //} catch(InterruptedIOException iioe) {
            //    daemon.displayMessage("Connection timed out to: " + hostName);
            //    /*
            //} catch(SocketException se) {
            //    daemon.displayMessage("Connection closed to: " + hostName);
            //} catch(EOFException eofe) {
            //    daemon.displayMessage("Connection closed to: " + hostName);
            //    */
            //} catch(IOException ioe) {
            //    daemon.displayMessage("Connection closed to: " + hostName +
            //              "  Reason: " + ioe.getClass().getName());
            //} catch(Exception e) {
            //    e.printStackTrace();
            //}
            //try {
            //    daemon.removeConnection(this);
            //    if(inputStream != null)
            //    inputStream.close();
            //    if(outputStream != null)
            //    outputStream.close();
            //    inputStream = null;
            //    outputStream = null;
            //    socket.shutdownInput();
            //    socket.shutdownOutput();
            //} catch(Exception e2) {
            //    daemon.displayMessage("Error while shutting down connection: " +
            //              e2);
            //    //e2.printStackTrace();
            //}
        }

        /// <summary>
        /// Runs this agent.
        /// </summary>
        protected override void ExecuteAgent()
        {
            //try {
            //    executeSocket();
            //} catch(Exception e) {
            //}
        }

        /// <summary>
        /// Sends the Agent off via this connection.
        /// </summary>
        /// <param name="agent">The Agent to send.</param>
        /// <param name="runState"></param>
        void transmitAgent( MobileAgent agent, int runState )
        {
            //try {
            //    if(outputStream == null) {
            //    synchronized(this) {
            //        if(outputStream == null)
            //        outputStream =
            //            new ObjectOutputStream(socket.getOutputStream());
            //    }
            //    }
            //    synchronized(this) {
            //    outputStream.writeObject(new AgentGram(agent, runState));
            //    resetCount++;
            //    if(resetCount >= 7) {
            //        outputStream.flush();
            //        outputStream.reset();
            //        resetCount = 0;
            //    }
            //    }
            //} catch(IOException ioe) {
            //    throw ioe;
            //} catch(Exception e) {
            //    throw new IOException("" + e);
            //}
        }

        /// <summary>
        /// Sends the AgentGram off via this connection.
        /// </summary>
        /// <param name="gram">The Agent to send.</param>
        void TransmitGram( AgentGram gram )
        {
            //try {
            //    if(outputStream == null) {
            //    synchronized(this) {
            //        if(outputStream == null)
            //        outputStream =
            //            new ObjectOutputStream(socket.getOutputStream());
            //    }
            //    }
            //    synchronized(this) {
            //    outputStream.writeObject(gram);
            //    resetCount++;
            //    if(resetCount >= 7) {
            //        outputStream.flush();
            //        outputStream.reset();
            //        resetCount = 0;
            //    }
            //    }
            //} catch(IOException ioe) {
            //    throw ioe;
            //} catch(Exception e) {
            //    throw new IOException("" + e);
            //}
        }

        /// <summary>
        /// Sends a DaemonDescription off via this connection.
        /// </summary>
        /// <param name="description">The Agent to send.</param>
        void TransmitDescription( DaemonDescription description )
        {
            //try {
            //    if(outputStream == null) {
            //    synchronized(this) {
            //        if(outputStream == null)
            //        outputStream =
            //            new ObjectOutputStream(socket.getOutputStream());
            //    }
            //    }
            //    synchronized(this) {
            //    outputStream.writeObject(description);
            //    resetCount++;
            //    if(resetCount >= 7) {
            //        outputStream.flush();
            //        outputStream.reset();
            //        resetCount = 0;
            //    }
            //    }
            //} catch(IOException ioe) {
            //    throw ioe;
            //} catch(Exception e) {
            //    throw new IOException("" + e);
            //}
        }

        /// <summary>
        /// Returns a description of the service.
        /// </summary>
        /// <returns></returns>
        public override string ShortDescription
        {
            get { return "SocketConnection to " + hostName + " on " + port; }
        }

        /// <summary>
        /// Returns a description of the service.
        /// </summary>
        /// <returns></returns>
        public override string AgentDescription
        {
            get { return ShortDescription; }
        }
    }
}
